package handlers

import (
	"fmt"
	"net/http"
	"ota-backend/config"
	"ota-backend/models"
	"strings"
	"time"

	"log"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"
)

// AuthHandler 认证处理器
type AuthHandler struct{}

// NewAuthHandler 创建认证处理器
func NewAuthHandler() *AuthHandler {
	return &AuthHandler{}
}

// LoginRequest 登录请求结构
type LoginRequest struct {
	Username string `json:"username" binding:"required"`
	Password string `json:"password" binding:"required"`
}

// LoginResponse 登录响应结构
type LoginResponse struct {
	Token     string `json:"token"`
	Username  string `json:"username"`
	ExpiresAt int64  `json:"expires_at"`
}

// Claims JWT声明结构
type Claims struct {
	Username string `json:"username"`
	jwt.RegisteredClaims
}

// OTAClaims OTA JWT声明结构
type OTAClaims struct {
	ProductID string `json:"pid"` // 产品ID
	SN        string `json:"sn"`  // 设备序列号
	Version   string `json:"v"`   // 版本信息
	jwt.RegisteredClaims
}

// Login 用户登录
func (h *AuthHandler) Login(c *gin.Context) {
	// 创建防爆破保护服务
	bfp := NewBruteForceProtection()

	// 获取客户端IP
	clientIP := bfp.GetClientIP(c)

	// 检查IP是否被封禁
	if bfp.IsIPBlocked(clientIP) {
		c.JSON(http.StatusTooManyRequests, gin.H{
			"error": "IP已被临时封禁，请稍后再试",
			"code":  "IP_BLOCKED",
		})
		return
	}

	var req LoginRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数错误"})
		return
	}

	// 验证用户名密码
	configUsername := config.GetAuthUsername()
	configPassword := config.GetAuthPassword()

	if req.Username != configUsername || req.Password != configPassword {
		// 记录登录失败
		bfp.RecordLoginFailure(c, req.Username)

		c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
		return
	}

	// 生成JWT token
	expiryHours := config.GetJWTExpiry()
	expiresAt := time.Now().Add(time.Duration(expiryHours) * time.Hour)

	claims := &Claims{
		Username: req.Username,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expiresAt),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			Issuer:    "ota-backend",
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	jwtSecret := config.GetJWTSecret()
	tokenString, err := token.SignedString([]byte(jwtSecret))
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "生成token失败"})
		return
	}

	// 登录成功，记录日志
	log.Printf("用户 %s 从 IP %s 登录成功", req.Username, clientIP)

	c.JSON(http.StatusOK, LoginResponse{
		Token:     tokenString,
		Username:  req.Username,
		ExpiresAt: expiresAt.Unix(),
	})
}

// VerifyToken 验证JWT token
func VerifyToken(tokenString string) (*Claims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(config.GetJWTSecret()), nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(*Claims); ok && token.Valid {
		return claims, nil
	}

	return nil, jwt.ErrInvalidKey
}

// AuthMiddleware JWT认证中间件
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 检查是否启用认证
		if !config.GetAuthEnabled() {
			c.Next()
			return
		}

		// 跳过OTA相关的接口
		path := c.Request.URL.Path
		if len(path) >= 4 && path[len(path)-4:] == "/ota" ||
			(len(path) > 4 && path[len(path)-5:] == "/ota/") ||
			(strings.Contains(path, "/ota/")) {
			c.Next()
			return
		}

		// 跳过登录接口 - 支持子路径，检查路径是否以/auth/login结尾
		if strings.HasSuffix(path, "/api/auth/login") {
			c.Next()
			return
		}

		// 获取Authorization header
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "缺少认证信息"})
			c.Abort()
			return
		}

		// 检查Bearer前缀
		const bearerPrefix = "Bearer "
		if len(authHeader) < len(bearerPrefix) || authHeader[:len(bearerPrefix)] != bearerPrefix {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "认证格式错误"})
			c.Abort()
			return
		}

		tokenString := authHeader[len(bearerPrefix):]

		// 验证token
		claims, err := VerifyToken(tokenString)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "认证失败"})
			c.Abort()
			return
		}

		// 将用户信息存储到上下文
		c.Set("username", claims.Username)
		c.Next()
	}
}

// VerifyOTAToken 验证OTA JWT token
func VerifyOTAToken(tokenString string, signKey string) (*OTAClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &OTAClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 确保使用HS512算法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}

		// 检查算法是否为HS512
		if token.Header["alg"] != "HS512" {
			return nil, fmt.Errorf("invalid algorithm, expected HS512, got %v", token.Header["alg"])
		}

		return []byte(signKey), nil
	})

	if err != nil {
		return nil, err
	}

	if claims, ok := token.Claims.(*OTAClaims); ok && token.Valid {
		return claims, nil
	}

	return nil, jwt.ErrInvalidKey
}

// OTAAuthMiddleware OTA JWT认证中间件
func OTAAuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取Authorization header
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "缺少认证信息"})
			c.Abort()
			return
		}

		// 检查Bearer前缀
		const bearerPrefix = "Bearer "
		if len(authHeader) < len(bearerPrefix) || authHeader[:len(bearerPrefix)] != bearerPrefix {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "认证格式错误"})
			c.Abort()
			return
		}

		tokenString := authHeader[len(bearerPrefix):]

		// 解析JWT获取产品ID（不验证签名，因为我们还不知道密钥）
		token, _, err := new(jwt.Parser).ParseUnverified(tokenString, &OTAClaims{})
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "JWT格式错误"})
			c.Abort()
			return
		}

		claims, ok := token.Claims.(*OTAClaims)
		if !ok {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "JWT claims格式错误"})
			c.Abort()
			return
		}

		if claims.ProductID == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "JWT中缺少产品ID"})
			c.Abort()
			return
		}

		// 根据产品ID查找产品和签名密钥
		var product models.Product
		if err := config.DB.First(&product, "public_id = ?", claims.ProductID).Error; err != nil {
			log.Printf("OTA认证失败: 产品不存在, public_id=%s, error=%v", claims.ProductID, err)
			c.JSON(http.StatusUnauthorized, gin.H{"error": "产品不存在"})
			c.Abort()
			return
		}

		if product.SignKey == "" {
			log.Printf("OTA认证失败: 产品签名密钥为空, public_id=%s", claims.ProductID)
			c.JSON(http.StatusUnauthorized, gin.H{"error": "产品签名密钥未配置"})
			c.Abort()
			return
		}

		// 使用产品的签名密钥验证JWT
		validClaims, err := VerifyOTAToken(tokenString, product.SignKey)
		if err != nil {
			log.Printf("OTA认证失败: JWT验证失败, public_id=%s, error=%v", claims.ProductID, err)
			c.JSON(http.StatusUnauthorized, gin.H{"error": "JWT验证失败"})
			c.Abort()
			return
		}

		// 将产品信息和claims存储到上下文
		c.Set("ota_product", &product)
		c.Set("ota_claims", validClaims)
		c.Set("product_id", validClaims.ProductID)
		c.Set("device_sn", validClaims.SN)
		c.Set("device_version", validClaims.Version)

		log.Printf("OTA认证成功: public_id=%s, sn=%s, version=%s", validClaims.ProductID, validClaims.SN, validClaims.Version)
		c.Next()
	}
}
